﻿using Volo.Abp.Domain;
using Volo.Abp.SqlSugarCore.SqlSugarFactory;
using SqlSugar;
using System;
using System.Collections.Generic;
using System.Text;
using Volo.Abp.Domain.Services;
using Volo.Abp.Users;
using Volo.Abp.Uow;
using Volo.Abp.SqlSugarCore.SqlSugarFactory.uow;
using Volo.Abp.Domain.Entities;
using Volo.Abp.Threading;
using Volo.Abp.MultiTenancy;
using Volo.Abp.Auditing;
using Volo.Abp.Data;
using Volo.Abp;
using System.Linq.Expressions;
using System.Collections.Concurrent;
using Volo.Abp.DependencyInjection;

namespace Volo.Abp.SqlSugarCore.Services
{
    public abstract class DalService : DomainService, IDalService, IUnitOfWorkEnabled, ITransientDependency
    {

        public ISqlSugarClient Db { get => AsyncHelper.RunSync<ISqlSugarClient>(() => LazyServiceProvider.LazyGetRequiredService<IUowSqlSugarFactory>().GetClient()); }
        protected ICurrentUser CurrentUser => LazyServiceProvider.LazyGetRequiredService<ICurrentUser>();

        protected IUnitOfWorkManager UnitOfWorkManager => LazyServiceProvider.LazyGetRequiredService<IUnitOfWorkManager>();
        protected IUnitOfWork CurrentUnitOfWork => UnitOfWorkManager?.Current;
        public IAuditPropertySetter AuditPropertySetter => LazyServiceProvider.LazyGetRequiredService<IAuditPropertySetter>();


        protected virtual Guid? CurrentTenantId => CurrentTenant?.Id;

        /// <summary>
        /// 合并group by 之后的字段值
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="str"></param>
        /// <returns></returns>
        public static string GroupConcat<T>(T str)
        {
            throw new NotSupportedException("Can only be used in expressions");
        }

        protected static IDictionary<string, List<string>> _entityPropertyNames = new ConcurrentDictionary<string, List<string>>();
        /// <summary>
        /// 初始化实体属性名称集合
        /// </summary>
        protected List<string> GetOrCreateEntityPropertyNames(Type entityType)
        {

            if (_entityPropertyNames.ContainsKey(entityType.Name))
            {
                return _entityPropertyNames[entityType.Name];
            }

            _entityPropertyNames[entityType.Name] = new List<string>();
            foreach (var itemPro in entityType.GetProperties())
            {
                _entityPropertyNames[entityType.Name].Add(itemPro.Name);
            }

            return _entityPropertyNames[entityType.Name];

        }

        protected ISugarQueryable<TEntity> GetAll<TEntity>()
        {
            var dataFilterStr = CreateFilterStr<TEntity>();
            return Db.Queryable<TEntity>().Where(dataFilterStr);
        }
        protected virtual void TryToSetTenantId<TEntity>(TEntity entity)
        {
            if (entity is IMultiTenant && HasTenantIdProperty(entity))
            {
                var tenantId = CurrentTenant.Id;

                if (!tenantId.HasValue)
                {
                    return;
                }

                var propertyInfo = entity.GetType().GetProperty(nameof(IMultiTenant.TenantId));

                if (propertyInfo == null || propertyInfo.GetSetMethod(true) == null)
                {
                    return;
                }

                propertyInfo.SetValue(entity, tenantId);
            }
        }
        protected virtual void ApplyAbpConceptsForDeletedEntity<TEntity>(TEntity entity)
        {
            if (!(entity is ISoftDelete))
            {
                return;
            }


            entity.As<ISoftDelete>().IsDeleted = true;
            SetDeletionAuditProperties(entity);
        }
        protected virtual bool HasTenantIdProperty<TEntity>(TEntity entity)
        {
            return entity.GetType().GetProperty(nameof(IMultiTenant.TenantId)) != null;
        }

        protected virtual Guid TrySetGuidId<TEntity>(TEntity entity)
        {

            if (entity is IEntity<Guid> entityWithGuidId)
            {
                if (entityWithGuidId.Id != default)
                {
                    return entityWithGuidId.Id;
                }
                EntityHelper.TrySetId(entityWithGuidId, () => GuidGenerator.Create());
                return entityWithGuidId.Id;
            }
            return GuidGenerator.Create();
        }

        protected virtual void SetCreationAuditProperties<TEntity>(TEntity entity)
        {
            AuditPropertySetter?.SetCreationProperties(entity);

            if (entity is ICreationNameObject objectWithCreationNameObject)
            {
                objectWithCreationNameObject.CreationName = CurrentUser.UserName;
            }
        }

        protected virtual void SetModificationAuditProperties<TEntity>(TEntity entity)
        {
            AuditPropertySetter?.SetModificationProperties(entity);
        }

        protected virtual void SetDeletionAuditProperties<TEntity>(TEntity entity)
        {
            AuditPropertySetter?.SetDeletionProperties(entity);
        }
        protected virtual string CreateFilterStr<TEntity>(string prix = "")
        {
            var entityType = typeof(TEntity);
            string whereCondition = "1=1";
            if (typeof(ISoftDelete).IsAssignableFrom(entityType))
            {
                whereCondition += $"&& {(prix.IsNullOrEmpty() ? "" : $"{prix}.")}{nameof(ISoftDelete.IsDeleted)}=0";
            }
            if (typeof(IMultiTenant).IsAssignableFrom(entityType))
            {
                whereCondition += $"&& {(prix.IsNullOrEmpty() ? "" : $"{prix}.")}{nameof(IMultiTenant.TenantId)}='{CurrentTenantId}'";
            }
            return whereCondition;
        }

        public DalService()
        {
        }
    }


    public abstract class DalService<TEntity> : DalService where TEntity : class, IEntity, new()
    {
        public ISimpleClient<TEntity> DbSet { get => new SimpleClient<TEntity>(Db); }

        public IDataFilter DataFilter => LazyServiceProvider.LazyGetRequiredService<IDataFilter>();
        protected virtual bool IsMultiTenantFilterEnabled => DataFilter?.IsEnabled<IMultiTenant>() ?? false;
        protected virtual bool IsSoftDeleteFilterEnabled => DataFilter?.IsEnabled<ISoftDelete>() ?? false;



        /// <summary>
        /// 实体属性名称集合
        /// </summary>
        public List<string> EntityPropertyNames { get => GetOrCreateEntityPropertyNames(typeof(TEntity)); }


        public DalService()
        {

        }


        protected ISugarQueryable<TEntity> GetAll()
        {
            return base.GetAll<TEntity>();
        }
        protected virtual void TryToSetTenantId(TEntity entity)
        {
            base.TryToSetTenantId(entity);
        }
        protected virtual bool HasTenantIdProperty(TEntity entity)
        {
            return base.HasTenantIdProperty(entity);
        }

        protected virtual Guid TrySetGuidId(TEntity entity)
        {

            return base.TrySetGuidId(entity);
        }

        protected virtual void SetCreationAuditProperties(TEntity entity)
        {
            base.SetCreationAuditProperties(entity);
        }

        protected virtual void SetModificationAuditProperties(TEntity entity)
        {
            base.SetModificationAuditProperties(entity);
        }

        protected virtual void SetDeletionAuditProperties(TEntity entity)
        {
            base.SetDeletionAuditProperties(entity);
        }


        protected virtual string CreateFilterStr(string prix = "")
        {
            return base.CreateFilterStr<TEntity>(prix);
        }
    }

}
